package com.motu.vertx.module.utility.logsdk;

import cn.thinkingdata.tga.javasdk.ThinkingDataAnalytics;
import com.alibaba.fastjson.JSONObject;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Map;
import java.util.TimeZone;

/**
 * 数数SDK数据采集（父类）
 */
public class ThinkingDataBaseManager {

	/**
	 * 注意事项：
	 * 不同事件的事件属性最好不要重名，因为一个属性只能有一个类型，如果有不同事件定义了相同属性名称，但是类型不同，那么属性类型会以第一个上报的为准，另外的事件上报可能就会失败
	 * 例如事件A定义type属性，是int类型（dataObj.put("type", type)） 事件B也定义type属性，是string类型（dataObj.put("type", String.valueOf(type))）
	 * 这种情况就是不允许的，如果都要用type属性，那么类型需要统一，最好是把type属性名称区分一下，例如a_type和b_type
	 */

	private static final Logger logger = LoggerFactory.getLogger(ThinkingDataBaseManager.class);

	public static int timeZoneOffset;//当前时区偏移

	// 预置属性
	public static final String TIME = "#time";//事件时间
	public static final String ZONE_OFFSET = "#zone_offset";//时区偏移
	public static final String ACCOUNT_ID = "#account_id";//账户id
	public static final String DISTINCT_ID = "#distinct_id";//访客id
	public static final String EVENT_NAME = "#event_name";//事件名
	public static final String EVENT_ID = "#event_id";//事件id
	public static final String DATA_TYPE = "#type";//上报事件类型
	public static final String IP = "#ip";//客户端ip
	public static final String DATA = "properties";

	// 公共事件
	public static final String EVENT_SYSTEM = "system";// 系统事件 比如adjust的投放成本
	public static final String EVENT_MONITOR_GATE = "monitor_gate";// 网关监控
	public static final String EVENT_MONITOR_KAFKA = "monitor_kafka";// kafka监控
	public static final String EVENT_AD_ADJUST_COST = "ad_adjust_cost";// adjust的买量花费

	public enum DataType {
		/**
		 * 上报事件
		 */
		TRACK("track"),
		/**
		 * 设置用户属性. 如果属性已经存在，则覆盖; 否则，新创建用户属性
		 */
		USER_SET("user_set"),
		/**
		 * 设置用户属性. 如果该属性已经存在，该操作无效
		 */
		USER_SET_ONCE("user_setOnce"),
		/**
		 * 用户属性修改，只支持数字属性增加的接口(比如等级+3)
		 * user_add不用发送#distinct_id，否则使用不同distinct_id可能会导致计算不准确
		 */
		USER_ADD("user_add"),
		/**
		 * 删除用户，此操作不可逆
		 */
		USER_DEL("user_del"),
		/**
		 * 删除用户指定的属性（特殊）
		 */
		USER_UNSET("user_unset"),
		/**
		 * 用户的数组类型的属性追加
		 */
		USER_APPEND("user_append"),
		/**
		 * 上报可被更新的事件属性
		 */
		TRACK_UPDATE("track_update"),
		/**
		 * 上报可被重写的事件
		 */
		TRACK_OVERWRITE("track_overwrite");

		private final String type;

		DataType(String type) {
			this.type = type;
		}

		public String getType() {
			return this.type;
		}
	}

	public static ThinkingDataAnalytics dataAnalytics;

	/**
	 * 初始化数数sdk
	 *
	 * @param appConfig
	 */
	public static void init(JsonObject appConfig) {

		// 初始化服务器时区偏移
		Calendar cal = Calendar.getInstance();
		TimeZone localTimezone = cal.getTimeZone();
		timeZoneOffset = localTimezone.getRawOffset();

		String appID = appConfig.getString("thinking-data-appid");
		String serverUrl = appConfig.getString("thinking-data-url");
		String gameName = appConfig.getString("bi-gameid");
		if (Tool.isEmpty(appID) || Tool.isEmpty(serverUrl) || Tool.isEmpty(gameName)) {
			return;
		}

		//测试用,正式使用请删除或者注释掉
		//serverUrl = "https://tgabi.m2time.net";
		//appID = "debug-appid";
		logger.info("ThinkingDataManager init gameName:{}，serverUrl:{},appID:{}", gameName, serverUrl, appID);
		ThinkingDataAnalytics.BatchConsumer.Config batchConfig = new ThinkingDataAnalytics.BatchConsumer.Config();
//        batchConfig.setAutoFlush(true);// 设置定时刷新
//        batchConfig.setInterval(5);// 定时时间，单位秒，默认值3
		batchConfig.setThrowException(true);
		//选填配置项
//        batchConfig.setBatchSize(30);//flush条数，默认20
		batchConfig.setCompress("gzip");//内网推荐none，默认gzip

		try {
			dataAnalytics = new ThinkingDataAnalytics(
					new ThinkingDataAnalytics.BatchConsumer(serverUrl, appID, batchConfig));
			if (dataAnalytics == null) {
				logger.error("ThinkingDataManager init error!! null");
			}
			setSuperProperties(gameName);

			// DebugConsumer一条一条的发送，用于测试数据格式是否正确，禁止线上使用！！！
			// 选填，是否入库，默认入库true
//             dataAnalytics = new ThinkingDataAnalytics(new ThinkingDataAnalytics.DebugConsumer(serverUrl, appID, false));
		} catch (Exception e) {
			logger.error(Tool.getException(e));
		}
	}

	public static void setSuperProperties(String gameName) {
		JSONObject commonData = new JSONObject();
		commonData.put("game_name", gameName);
		Map<String, Object> properties = commonData.getInnerMap();
		dataAnalytics.setSuperProperties(properties);
	}

	/**
	 * 模拟kafka用的发送逻辑
	 * <p>发送后入库延时1~2分钟左右
	 */
	public static void send(String recordValue) {
		try {
			// ThinkingDataSDK，用的是alibaba.fastjson
//            logger.info("ThinkingDataManager.send recordValue:{}",recordValue);
			JSONObject obj = JSONObject.parseObject(recordValue);
			if (obj != null) {
				String accountId = obj.containsKey(ACCOUNT_ID) ? obj.getString(ACCOUNT_ID) : "";
				String distinctId = obj.containsKey(DISTINCT_ID) ? obj.getString(DISTINCT_ID) : "";
				String eventName = obj.containsKey(EVENT_NAME) ? obj.getString(EVENT_NAME) : "";
				String eventId = obj.containsKey(EVENT_ID) ? obj.getString(EVENT_ID) : "";
				String dataType = obj.containsKey(DATA_TYPE) ? obj.getString(DATA_TYPE) : "";
				JSONObject data = obj.containsKey(DATA) ? obj.getJSONObject(DATA) : new JSONObject();
				Map<String, Object> properties = data.getInnerMap();
				if (obj.containsKey(TIME)) {// 有设置#time, 塞到properties, 避免被数数默认成接收数据时的时间
					properties.put(TIME, obj.getString(TIME));
				}
				if (obj.containsKey(IP)) {// 有设置#ip, 塞到properties
					properties.put(IP, obj.getString(IP));
				}
				if (obj.containsKey(ZONE_OFFSET)) {//有设置#zone_offset, 塞到properties
					if (!obj.getString(ZONE_OFFSET).isEmpty()) {
						properties.put(ZONE_OFFSET, Float.parseFloat(obj.getString(ZONE_OFFSET)));
					}
				}
				if (accountId.isEmpty() && distinctId.isEmpty()) {
					// 两个必须要有一个值
					logger.error("ThinkingData recordValue ={}, accountId And distinctId isEmpty!!!!!!", recordValue);
					return;
				}

				if (DataType.TRACK.getType().equals(dataType)) {
					if (eventName.isEmpty()) {
						// 事件名称不能为空
						logger.error("ThinkingData dataType = " + dataType + ", eventName isEmpty!!!!!!");
						return;
					} else {
						dataAnalytics.track(accountId, distinctId, eventName, properties);
					}
				} else if (DataType.USER_SET.getType().equals(dataType)) {
					dataAnalytics.user_set(accountId, distinctId, properties);
				} else if (DataType.USER_SET_ONCE.getType().equals(dataType)) {
					dataAnalytics.user_setOnce(accountId, distinctId, properties);
				} else if (DataType.USER_ADD.getType().equals(dataType)) {
					dataAnalytics.user_add(accountId, distinctId, properties);
				} else if (DataType.USER_DEL.getType().equals(dataType)) {
					dataAnalytics.user_del(accountId, distinctId);
				} else if (DataType.USER_UNSET.getType().equals(dataType)) {
					String[] useUnsetKeys = properties.containsKey("user_unset_keys")
							? (String[]) properties.get("user_unset_keys") : new String[0];
					if (useUnsetKeys.length == 0) {
						// 重置key不能为空
						logger.error("ThinkingData dataType = " + dataType + ", useUnsetKeys isEmpty!!!!!!");
						return;
					} else {
						dataAnalytics.user_unset(accountId, distinctId, useUnsetKeys);
					}
				} else if (DataType.USER_APPEND.getType().equals(dataType)) {
					dataAnalytics.user_append(accountId, distinctId, properties);
				} else if (DataType.TRACK_UPDATE.getType().equals(dataType)) {
					dataAnalytics.track_update(accountId, distinctId, eventName, eventId, properties);
				} else if (DataType.TRACK_OVERWRITE.getType().equals(dataType)) {
					dataAnalytics.track_overwrite(accountId, distinctId, eventName, eventId, properties);
				} else {
					// 数据发送类型不存在
					logger.error("ThinkingData dataType = " + dataType + ", no exits!!!!!!");
					return;
				}
				dataAnalytics.flush();
			}
		} catch (Exception e) {
			logger.error(Tool.getException(e));
		}
	}


	/*****************  事件数据 *******************/


	/**
	 * adjust的投放成本数据
	 *
	 * @param appcode adjust的投放包的应用id
	 * @param date    统计日期.2021-07-01
	 * @param cost    这天的花费金额
	 */
	public static void pushAdjstCost(String appcode, String date, Double cost) {
		// ThinkingDataSDK，用的是alibaba.fastjson
		JSONObject params = new JSONObject();
		params.put(ACCOUNT_ID, EVENT_SYSTEM);
		params.put(EVENT_NAME, EVENT_AD_ADJUST_COST);
		params.put(EVENT_ID, appcode + "." + date);// appid和日期组成唯一事件id
		params.put(DATA_TYPE, DataType.TRACK_UPDATE.getType());// 可更新事件
		params.put(TIME, date + " 23:59:59.000");

		// 事件参数
		JSONObject eventParams = new JSONObject();
		eventParams.put("ad_buy_id", appcode);//  adjust投放包的appid
		eventParams.put("ad_buy_cost", cost);// 花费金额

		params.put(DATA, eventParams);
		LogSDKManager.sendThinkingData(LogSDKManager.KAFKA_TOPIC_THINKINGDATA, params);
	}

	/**
	 * 发送网关监控数据到数数
	 *
	 * @param jsonObject
	 */
	public static void pushMonitorGate(JsonObject jsonObject) {
		// ThinkingDataSDK，用的是alibaba.fastjson
		JSONObject params = new JSONObject();
		params.put(ACCOUNT_ID, "system_monitor_gate");
		params.put(EVENT_NAME, EVENT_MONITOR_GATE);
		params.put(DATA_TYPE, DataType.TRACK.getType());//
		if (jsonObject.containsKey("addtime")) {
			params.put(TIME, TimeUtils.getTimeFullStr(jsonObject.getLong("addtime")) + ".000");
		}

		// 事件参数
		JSONObject eventParams = new JSONObject();
		try {
			int gate_queue_num = jsonObject.getInteger("gate_queue_num");
			int socket_num = jsonObject.getInteger("socket_num");
			int package_num = jsonObject.getInteger("package_num");
			int init_num = jsonObject.getInteger("init_num");
			int timeout_num = jsonObject.getInteger("timeout_num");
			long addtime = jsonObject.getLong("addtime");
			double request_ave = jsonObject.getDouble("request_ave");
			double response_ave = jsonObject.getDouble("response_ave");
			double deal_ave = jsonObject.getDouble("deal_ave");
			double init_response_ave = jsonObject.getDouble("init_response_ave");
			double init_deal_ave = jsonObject.getDouble("init_deal_ave");

			eventParams.put("gate_queue_num", gate_queue_num);
			eventParams.put("socket_num", socket_num);
			eventParams.put("package_num", package_num);
			eventParams.put("init_num", init_num);
			eventParams.put("timeout_num", timeout_num);
			eventParams.put("addtime", addtime);
			eventParams.put("request_ave", request_ave);
			eventParams.put("response_ave", response_ave);
			eventParams.put("deal_ave", deal_ave);
			eventParams.put("init_response_ave", init_response_ave);
			eventParams.put("init_deal_ave", init_deal_ave);
		} catch (Exception e) {
			eventParams.put("package_num", 0);// 当报错异常时.发送包=0 的数据
			eventParams.put("init_num", 0);
		}

		params.put(DATA, eventParams);
		LogSDKManager.sendThinkingData(LogSDKManager.KAFKA_TOPIC_THINKINGDATA, params);
	}

	/**
	 * 发送kafka监控数据到数数
	 *
	 * @param jsonObject
	 */
	public static void pushMonitorKafka(JsonObject jsonObject) {
		// ThinkingDataSDK，用的是alibaba.fastjson
		JSONObject params = new JSONObject();
		params.put(ACCOUNT_ID, "system_monitor_kafka");
		params.put(EVENT_NAME, EVENT_MONITOR_KAFKA);
		params.put(DATA_TYPE, DataType.TRACK.getType());//
		if (jsonObject.containsKey("addtime")) {
			params.put(TIME, TimeUtils.getTimeFullStr(jsonObject.getLong("addtime")) + ".000");
		}

		// 事件参数
		JSONObject eventParams = new JSONObject();
		int db_num = jsonObject.getInteger("db_num");
		int adjust_num = jsonObject.getInteger("adjust_num");
		int log_num = jsonObject.getInteger("log_num");
		int mob_num = jsonObject.getInteger("mob_num");
		int reyun_num = jsonObject.getInteger("reyun_num");
		long addtime = jsonObject.getLong("addtime");
		int toutiao_num = jsonObject.getInteger("toutiao_num");
		int shushu_num = jsonObject.getInteger("shushu_num");
		eventParams.put("db_num", db_num);
		eventParams.put("adjust_num", adjust_num);
		eventParams.put("log_num", log_num);
		eventParams.put("mob_num", mob_num);
		eventParams.put("reyun_num", reyun_num);
		eventParams.put("addtime", addtime);
		eventParams.put("toutiao_num", toutiao_num);
		eventParams.put("shushu_num", shushu_num);

		params.put(DATA, eventParams);
		LogSDKManager.sendThinkingData(LogSDKManager.KAFKA_TOPIC_THINKINGDATA, params);
	}

}
